package com.qire.common.constant;

import android.app.Application;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;

import com.qire.antsrouter.lifecycleHandler.ActivityManageHandler;
import com.qire.common.basic.ObjectUtil;
import com.qire.common.collect.ListUtil;
import com.qire.common.utils.EquipmentInfoUtil;
import com.qire.other.advert.Advert;
import com.qire.other.advert.AdvertFactory;
import com.qire.other.advert.AdvertDockingDevice;
import com.qire.other.advert.Advertiser;
import com.qire.other.advert.impl.PangolinAdvert;

import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import androidx.annotation.Nullable;

/**
 * 广告管理器:
 * <p>主要用于管理：</p>
 * <pre>
 *  1.管理广告位置
 *  2.管理广告厂商
 *  3.预加载相关位置上的广告。
 *  4.按一定规则从对应广告位上取出广告。
 * </pre>
 */
public final class AdvertManage {

    private static final ExecutorService LoadAdvertTaskPool = Executors.newCachedThreadPool(runnable -> new Thread(runnable, "AdvertManage的工作线程：" + runnable));

    static {
        AdvertSpace.AppSplash.putAdvert(Advertiser.PANGOLIN, "887320821", 1, 1);
        AdvertSpace.ComicUnlock.putAdvert(Advertiser.PANGOLIN, "945162651", 1, 1);
        AdvertSpace.TaskDoubleReceive.putAdvert(Advertiser.PANGOLIN, "945162651", 1, 1);
    }

    private AdvertManage() {
        throw new UnsupportedOperationException("不能初始化这个工具 : AdvertManage");
    }

    /**
     * 所有的第三方广告SDK初始化应该都写在这里，方便集中管理。
     * @param application 应用实例
     */
    public static void init(Application application) {
        PangolinAdvert.init(application);
    }

    /**
     * 根据 广告位代码 获得 广告位
     * @param spaceCode 广告位代码
     * @return 广告位
     */
    public static AdvertSpace findAdvertSpace(String spaceCode) {
        switch (spaceCode) {
            case "AppSplash" :
                return AdvertSpace.AppSplash;
            case "ComicUnlock" :
                return AdvertSpace.ComicUnlock;
            case "READ_MIDDLE_XXL" :
                return AdvertSpace.ComicBetween;
        }
        return AdvertSpace.UNKNOWN;
    }

    /**
     * 广告位
     */
    public enum AdvertSpace {

        /** 未知 */
        UNKNOWN(),
        /** APP启动入场广告 */
        AppSplash(),
        /** 漫画阅读解锁激励视频广告 */
        ComicUnlock(),
        /** 漫画阅读中间的信息流广告 */
        ComicBetween(),
        /** 任务双倍领取 */
        TaskDoubleReceive();

        /** 广告位上可以使用的相关广告信息列表，广告位展示的广告可以通过从该列表中按比例被一次展示 */
        private final ArrayList<AdvertInfo> advertInfoList = new ArrayList<>();

        /** 广告位上预加载的广告装载器，这个会预先申请一个广告，并在未来使用他 */
        private FutureAdvertDockingDevice readyAdvertViewBinder = new FutureAdvertDockingDevice();

        AdvertSpace() {}

        /**
         * 填充广告位中的广告信息列表，这个可能是初始化写死，也可以在后续通过API从服务器获得
         * @param advertiser 广告商
         * @param code  广告代码
         * @param ratio 展示占比
         * @param maxRatio 总次数占比。
         */
        public void putAdvert(Advertiser advertiser, String code, int ratio, int maxRatio) {
            advertInfoList.add(new AdvertInfo(advertiser, code, ratio, maxRatio));
        }

        /**
         * 从广告信息列表池中获得一个广告信息。按照指定比例规则。
         * @return 广告信息
         */
        private AdvertInfo findAdvertOnPool() {
            if (ListUtil.isEmpty(advertInfoList)) {
                return new AdvertInfo();
            }

            AdvertInfo advertiseInfo = null;

            for (AdvertInfo info : advertInfoList) {
                info.countQuery();
                if (ObjectUtil.isNull(advertiseInfo)) {
                    advertiseInfo = info;
                } else if(advertiseInfo.compare(info)) {
                    advertiseInfo = info;
                }
            }

            advertiseInfo.countShow();
            return advertiseInfo;
        }

        /**
         * 按照比例分配构建一个广告实体对象
         * @return 广告实体对象
         */
        public Advert build() {
            AdvertInfo info = findAdvertOnPool();
            return AdvertFactory.create(info.advertiser, info.code);
        }

        /**
         * 预加载一个广告实体对象
         */
        public void onReadyAdvert() {
            readyAdvertViewBinder = new FutureAdvertDockingDevice();
            LoadAdvertTaskPool.submit(() -> build().setSize(EquipmentInfoUtil.getScreenWidth(), 0).injectionInfoFlow(readyAdvertViewBinder));
        }

        public FutureAdvertDockingDevice readyAdvert() {
            FutureAdvertDockingDevice nowUseAdvertViewBinder = readyAdvertViewBinder;
            onReadyAdvert();
            return nowUseAdvertViewBinder;
        }

        /**
         * 在未来使用的广告视图绑定器。
         */
        public class FutureAdvertDockingDevice implements AdvertDockingDevice {
            private View advertView;
            private ViewGroup advertContainer;

            public boolean isValid() {
                return ObjectUtil.nonNull(advertView);
            }
            public boolean isContainerValid() {
                return ObjectUtil.nonNull(advertContainer);
            }

            public void setAdvertContainer(ViewGroup advertContainer) {
                this.advertContainer = advertContainer;
                doFillContainer();
            }

            private void doFillContainer() {
                if(isValid() && isContainerValid()) {
                    advertContainer.post(() -> {
                        remove(advertView);
                        advertContainer.removeAllViews();
                        advertContainer.addView(advertView);
                        destroy();
                    });
                }
            }

            @Override
            public Context getContext() {
                return ActivityManageHandler.HANDLER.currentActivity();
            }

            @Override
            public void insert(View advertView) {
                this.advertView = advertView;
                doFillContainer();
            }

            @Override
            public void remove(View advertView) {
                if(ObjectUtil.nonNull(advertView)) {
                    ViewGroup advertViewParent = (ViewGroup)advertView.getParent();
                    if(ObjectUtil.nonNull(advertViewParent)) {
                        advertViewParent.removeView(advertView);
                    }
                }
            }

            @Override
            public void removeAll() {
                if(ObjectUtil.nonNull(advertView)) {
                    ViewGroup parent = (ViewGroup) advertView.getParent();
                    if(ObjectUtil.nonNull(parent)) {
                        parent.removeAllViews();
                    }
                }
            }

            @Override
            public void destroy() {
                this.advertView = null;
                this.advertContainer = null;
            }
        }

        /**
         * 广告配置信息
         */
        public class AdvertInfo {
            /**
             * 广告商
             */
            public final Advertiser advertiser;
            /**
             * 广告代码
             */
            public final String code;
            /**
             * 广告占比
             */
            public final int ratio;
            /**
             * 广告总比
             */
            public final int maxRatio;

            private int countQuery = 0;
            private int countShow = 0;

            public AdvertInfo() {
                this(Advertiser.UNKNOWN, "", 0, 0);
            }

            public AdvertInfo(Advertiser advertiser, String code, int ratio, int maxRatio) {
                this.advertiser = advertiser;
                this.code = code;
                this.ratio = ratio;
                this.maxRatio = maxRatio;
            }

            private void reset() {
                countQuery = 0;
                countShow = 0;
            }

            private boolean compare(AdvertInfo info) {
                if (this.countShow >= ratio) {
                    return true;
                }
                return this.countShow > info.countShow;
            }

            private void countQuery() {
                if (countQuery >= maxRatio) {
                    reset();
                }
                countQuery++;
            }

            private void countShow() {
                countShow++;
            }

            @Override
            public boolean equals(@Nullable Object obj) {
                if(obj == null) {
                    return false;
                }
                if(obj instanceof AdvertInfo) {
                    AdvertInfo info = (AdvertInfo) obj;
                    return this.advertiser.equals(info.advertiser) && this.code.equals(info.code);
                }
                return super.equals(obj);
            }
        }

    }

}
